import cv2
import os
import shutil
class ExtractVidioFrameToImage():
    def extract_video_frame(self, video_src_path, output_save_folder):
        cap = self.__get_capture__(video_src_path)
       
        
        frame_index = 0
        print("start extract frame...")
        while True:
            # 逐帧捕获
            ret, frame = cap.read()
            if not ret:
                # 到达视频末尾或出现错误
                print("End Of Stream Read!")
                break
            
            print("current frame index: " + str(frame_index))
            img_name = str(frame_index).rjust(4, "0") + ".jpg"
            save_image_path = os.path.join(output_save_folder, img_name)
            cv2.imwrite(save_image_path, frame)
            
            frame_index += 1
        print("extract frame completely!")
        # 完成后释放资源
        cap.release()
        cv2.destroyAllWindows()
        
    def __get_capture__(self, video_src_path):
            # 打开视频文件或摄像头
            # 如果这里指定的设备索引号，来实现采集指定摄像头的图像；需要注意使用cv2.CAP_DSHOW（指定 DirectShow 作为后端）
            # 则可以很快进入摄像头图像采集；采用参数cv2.CAP_MSMF，或者不指定参数都会比较卡，推测可能是因为摄像头不支持MSMF，
            # MSMF（Windows Media Foundation）是微软推出的新一代的多媒体框架，版本较老的摄像头会不支持。
            # 如果是Linux则采用CV2.CAP_V4L2
            if isinstance(video_src_path, int):
                cap = cv2.VideoCapture(video_src_path, cv2.CAP_DSHOW)
            else:
                cap = cv2.VideoCapture(video_src_path)

            # 检查是否成功打开
            if not cap.isOpened():
                print("open video src ERROR! return")
                cap = None
                
            return cap
        
    def __get_capture__(self, video_src_path):
            # 打开视频文件或摄像头
            # 如果这里指定的设备索引号，来实现采集指定摄像头的图像；需要注意使用cv2.CAP_DSHOW（指定 DirectShow 作为后端）
            # 则可以很快进入摄像头图像采集；采用参数cv2.CAP_MSMF，或者不指定参数都会比较卡，推测可能是因为摄像头不支持MSMF，
            # MSMF（Windows Media Foundation）是微软推出的新一代的多媒体框架，版本较老的摄像头会不支持。
            # 如果是Linux则采用CV2.CAP_V4L2
            if isinstance(video_src_path, int):
                cap = cv2.VideoCapture(video_src_path, cv2.CAP_DSHOW)
            else:
                cap = cv2.VideoCapture(video_src_path)

            # 检查是否成功打开
            if not cap.isOpened():
                print("open video src ERROR! return")
                cap = None
                
            return cap
        
    def __get_output_writer__(self, cap, output_save_folder, frame_index):
        # 获取视频的属性
        fps = int(cap.get(cv2.CAP_PROP_FPS))
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

        fourcc = cv2.VideoWriter_fourcc(*'MP4V')  # 可根据需要选择合适的编码器
        img_name = str(frame_index).rjust(4, "0")
        save_image_path = os.path.join(output_save_folder, img_name)
        writer = cv2.VideoWriter(save_image_path, fourcc, fps, (width, height))
            
        return writer
    
    def sample_from_full(self, img_src_folder, img_target_folder, skip_count):
        # 如果既存目录，删除后再拷贝采样图像文件
        if os.path.exists(img_target_folder):
            shutil.rmtree(img_target_folder)
            
        os.mkdir(img_target_folder)
        # 统计目标目录下图片文件总数
        with os.scandir(img_src_folder) as entries:
            file_count = sum(1 for entry in entries if entry.is_file())
        print("image file path: " + str(file_count))
        
        # 根据需要采样拷贝图像文件
        frame_index = 1
        copyed_file_count = 0
        print("starting copy...")
        while frame_index <= file_count:
            img_name = "".join(["frame", str(frame_index).rjust(5, "0"), ".jpg"])
            img_src_path = os.path.join(img_src_folder, img_name)
            shutil.copy(img_src_path, img_target_folder)
            frame_index += skip_count
            
            copyed_file_count += 1
        print("copyed file count: " + str(copyed_file_count))
        
if __name__ == "__main__":
    app = ExtractVidioFrameToImage()
    # src_video_path = "2025-04-03 020009.mov"
    # image_dest_path = "images"
    # app.extract_video_frame(src_video_path, image_dest_path)
    image_src_path = "images_full"
    image_dest_path = "images"
    app.sample_from_full(image_src_path, image_dest_path, 5)